#include "fxcc/core/graph/common/pch.h"
#include "fxcc/core/graph/opengl3/pch.h"
#include "fxcc/core/AssertManager.h"
#include "fxcc/core/Dir.h"
#include "sysx/System.h"
#include "fxcc/core/Dir.h"

#undef main

struct TextureImporter
{
	std::string m_LibraryPath{ "Library" };

	bool Import(const std::string& file) const
	{
		if(!fs::exists(file))
		{
			return false;
		}
		
		const std::string suffix = fxcc::Base::GetSuffix(file);
		if (fxcc::FileUtil::IsDDSImage(suffix))
		{
			return ImportDDS(file);
		}
		else
		{
			return ImportWIC(file);
		}
	}
	bool ImportDDS(const std::string& file) const {
	
	fs::path _dir = m_LibraryPath / fs::path("Image");
		std::string _dirStr = _dir.string();
		std::string targetFileName = fxcc::FileUtil::getTargetPath(file, "", ".dds");
		fs::path targetFilePath = _dir / fs::path(targetFileName);

		fxcc::Base::CreateParentDirs(targetFilePath.string());
		fs::rename(file, targetFilePath);

		return true;
	}
	bool ImportWIC(const std::string& file) const
	{
		std::string fileName = fs::path(file).filename().string();
		std::string fileNameNoSuffix = fxcc::Base::GetNoSuffixName(fileName);

		fs::path _dir = m_LibraryPath / fs::path("Image");

		std::string _dirStr = _dir.string();

		std::string targetFileName = fxcc::FileUtil::getTargetPath(file, "", ".dds");
		fs::path targetFilePath = _dir / fs::path(targetFileName);

		fxcc::Base::CreateParentDirs(targetFilePath.string());

		kainjow::mustache::mustache m1 = std::string(R"(texconv -f BC3_UNORM -o  {{{targetDir}}} {{{source}}})");

		kainjow::mustache::data d1;

		d1.set("source", file);
		d1.set("targetDir", _dirStr);

		std::cout << m1.render(d1) << std::endl;
		sysx::System::ExecuteCmd(m1.render(d1));

		fs::path currentFilePath = fs::path(_dirStr) / (fileNameNoSuffix + ".dds");
		fs::path targetPath = fs::path(_dirStr) / targetFileName;

		if (fs::exists(targetFilePath))
			fs::remove(targetFilePath);

		fs::rename(currentFilePath, targetFilePath);
		return true;
	}
};


struct AudioImporter
{
	std::string m_LibraryPath{ "Library" };

public:

	bool Import(const std::string& file)
	{
		if (!fs::exists(file))
		{
			return false;
		}
		std::string fileName = fs::path(file).filename().string();

		fs::path _dir = m_LibraryPath / fs::path("Audio");

		std::string _dirStr = _dir.string();

		std::string targetFileName = fxcc::FileUtil::getTargetPath(file, "", ".ogg");

		fs::path _targetPath = fs::path(_dirStr) / targetFileName;

		fxcc::Base::CreateParentDirs(_targetPath.string());

		kainjow::mustache::mustache m1 = std::string(

			R"(ffmpeg -y  -i {{{source}}} -c:a libvorbis {{{targetPath}}})"
		);
		kainjow::mustache::data d1;

		d1.set("source", file);
		d1.set("targetPath", _targetPath.string());

		sysx::System::ExecuteCmd(m1.render(d1));

	}

};

struct ModelImporter
{
	std::string m_LibraryPath{ "Library" };

	std::string GetMetaFile(const std::string& path) const
	{
		fs::path _p = fs::path(".meta") / fs::path(path);
		return _p.string();
	}
	bool HasImportFile(const std::string& p) const
	{
		auto metaFile = GetMetaFile(p);
		return fs::exists(metaFile);
	}

	bool ImportModel(const fxcc::File& _p) const
	{
		return ImportModel(_p.m_RelativePath);
	}

	bool ImportModel(const std::string& _p) const
	{
		static fxcc::yml::Serializer serializer;

		fs::path m_FilePath(m_LibraryPath);

		auto scene = std::make_shared<fxcc::graph::common::Scene>(_p);
		const std::string sceneName = scene->m_Name;

		{
			fs::path _meshdataDir = m_FilePath / fs::path("Mesh");
			fs::path _boneDataDir = m_FilePath / fs::path("Bones");

			for (int i = 0; i < scene->m_MeshDatas.size(); i++)
			{

				const auto& meshData = scene->m_MeshDatas[i];

				fs::path _meshPath = _meshdataDir / fs::path(fxcc::FileUtil::getTargetPath(_p, meshData->m_Name , ".mesh"));
				FXCC_FAILED(meshData->m_GeoDataPtr->WriteToFile(_meshPath.string()));

				if (meshData->HasBones())
				{
					std::string skinnedDataFileName = fxcc::FileUtil::getTargetPath(_p, meshData->m_Name, ".skinned");
					std::string boneDataFileName = fxcc::FileUtil::getTargetPath(_p, meshData->m_Name, ".bone");

					fs::path _skinnedDataPath = _meshdataDir / fs::path(skinnedDataFileName);
					fs::path _boneDataPath = _boneDataDir / fs::path(boneDataFileName);


					FXCC_FAILED(meshData->m_SkinnedMeshDataPtr->WriteToFile(_skinnedDataPath.string()));
					FXCC_FAILED(serializer.EncodePath<fxcc::graph::common::Bones>(_boneDataPath.string(), *meshData->m_Bones));

				}

			}
		}

		{
			fs::path _p1 = m_FilePath / fs::path("Material");

			for (int i = 0; i < scene->m_Materials.size(); i++)
			{
				auto inst = scene->m_Materials[i];

				fs::path _thisPath = _p1 / fs::path(inst->m_Name + ".mat");

				FXCC_FAILED(serializer.EncodePath<fxcc::graph::common::MaterialData>(_thisPath.string(), *inst));
			}
		}
		{
			fs::path _p1 = m_FilePath / fs::path("Animation");

			for (int i = 0; i < scene->m_Animations.size(); i++)
			{
				auto inst = scene->m_Animations[i];
				fs::path _thisPath = _p1 / fxcc::FileUtil::getTargetPath(_p, inst->m_Name, ".amim");
				FXCC_FAILED(serializer.EncodePath<fxcc::graph::common::Animation>(_thisPath.string(), *inst));
			}
		}
		return true;
	};

};

int main()
{

	ztclog::pushFunction([=](const ztclog::Line& l) {

		std::cout << l.m_Text << std::endl;
		});

	if (1)
	{

		ModelImporter importer;

		std::string _p = fxcc::AssertManager::GetRelativeFile("Model/Sponza/sponza.gltf");
		std::string _p2 = fxcc::AssertManager::GetRelativeFile("Anim/Walking.fbx");
		std::string _p3 = fxcc::AssertManager::GetRelativeFile("cube.fbx");

		bool flag = importer.ImportModel(_p);
		FXCC_FAILED_X(flag, "Failed import model");
		FXCC_FAILED_X(importer.ImportModel(_p2), "Failed import model");
		FXCC_FAILED_X(importer.ImportModel(_p3), "Failed import model");
	}

	if (1)
	{
		AudioImporter importer;

		bool flag{ 0 };
		std::string _p = fxcc::AssertManager::GetRelativeFile("audio/demo1.mp3");
		flag = importer.Import(_p);
	}
	if (1)
	{
		TextureImporter importer;
		std::string _p = fxcc::AssertManager::GetRelativeFile("Texture/daylight0.png");
		
		bool flag = importer.Import(_p);

	}
	return 0;
}
